<?php
namespace Plu\Library\Services\RPC;

use Plu\Library\Services\ServiceBase,
    Plu\Grpc\Services\RCS\Client\RCSClient,
    Plu\Grpc\Services\RCS\Page,
    Plu\Grpc\Services\RCS\Location,
    Plu\Library\Services\Redis\Room\RoomRedis,
    Plu\Library\Services\Platform\Game\GamesService;

class RCSService extends ServiceBase {
    protected $layoutId   = 0;
    protected $device     = 0;
    protected $location   = null;
    protected $page       = null;
    protected $gameId     = 0;
    protected $layoutKey  = '';
    protected $metadata   = [];
    protected $options    = [];
    protected $lastCursor = 0;
    protected $layout     = null;

    private $client;
    private $gamesService;
    private $roomRedis;
    private $exists = true;

    const ERR_LAYOUT_NOT_EXISTS = 2;

    public function __construct() {
        $this->gamesService = new GamesService();
        $this->roomRedis = new RoomRedis;
    }

    public function setLayoutId($id){
        $this->layoutId = $id;

        return $this;
    }

    public function setLayoutKey($key){
        $this->layoutKey = $key;

        return $this;
    }


    public function setDevice($deviceId){
        $this->device = $deviceId;

        return $this;
    }

    public function setLocation($distance = 0, $latitude = 0.0, $longtitude = 0.0){
        $location = new Location();
        $location->setDistance($distance);
        $location->setLatitude($latitude);
        $location->setLongtitude($longtitude);

        $this->location = $location;

        return $this;
    }

    public function setGameId($gameid){
        $this->gameId = $gameid;

        return $this;
    }

    public function setPage($cursor = 0, $pageSize = 10){
        $page = new Page();
        $page->setPageSize($pageSize);
        $page->setCursor($cursor);
        $this->page = $page;
        return $this;
    }


    public function reset() {
        $this->layoutId    = 0;
        $this->device      = 0;
        $this->location    = null;
        $this->page        = null;
        $this->gameId      = 0;
        $this->layoutKey   = '';
        $this->layout      = null;
        $this->lastCursor  = 0;

        return $this;
    }

    private function getGuid() {
        return md5(json_encode([
            $this->layoutId,
            $this->device,      
            $this->location,    
            $this->page,        
            $this->gameId,      
            $this->layoutKey,   
            $this->layout,      
            $this->lastCursor,  
        ]));
    }

    public function isExists() {
        return $this->exists;
    }

    public function getStages() {
        return $this->layout->getStages();
    }

    public function getTotalStageCount() {
        return $this->layout->getStageCount();
    }

    public function getLayoutId() {
        return  $this->layout->getLayoutId();
    }
    

    private function getStage() {
        foreach ($this->layout->getStages() as $stage) {
            $item = [
                'id' => $stage->getId(),
                'linkLayoutId' => $stage->getLinkLayoutId(),
                'type' => $stage->getType(),
                'stageKey' => $stage->getStageKey(),
                'key' => $stage->getKey(),
                'image' => $stage->getImage(),
                'title' => $stage->getTitle(),
                'link'  => $stage->getLinkUrl(),
                'sort'  => $stage->getSort(),
                'positions' => $this->getPositions($stage)
            ];

            yield $item;
        }
    }

    private function getPositions($stage) {
        $items = [];
        foreach ($stage->getPositions() as $position) {
            foreach ($this->getResources($position) as $item) {
                $items[] = $item;
            }
        }
        return $items;
    }

    private function getResources($position) {
        foreach ($position->getResources() as $resource) {
            yield $this->getResourceData($resource);
        }
    }

    private function getResourceData($resource) {
        $data['title'] = $resource->getTitle();
        $data['cover'] = $resource->getCover();
        $data['stick'] = $resource->getStick();
        $data['isAd'] = $resource->getIsAd();
        $data['link'] = $resource->getLink();
        $data['linkType'] = $resource->getLinkType();
        $data['iconWords'] = $resource->getIconWords();
        $data['isDynamic'] = $resource->getIsDynamic();
        $data['cursor'] = $resource->getCursor();

        //$data['advert'] = $this->advert($resource);
        $data['game'] = $this->game($resource);
        $data['match'] = $this->match($resource);

        $data['room'] = $this->roomInfo($resource);
        $data['user'] = $this->userInfo($resource);
        $data['location'] = $this->location($resource);

        //$data['getRoomSource'] = $resource->getRoomSource()->getRank();

        $this->lastCursor = $data['cursor'];
        return $data;
    }

    public function getLayout() {
        $guid = sprintf("rcs.%s", $this->getGuid());

        try {
            if (is_null($this->client)) {
                $this->client = $this->grpc->service("go.micro.srv.rcs");
            }
            $layout = $this->client->LayoutData($this->layoutId, $this->device, $this->location, $this->page, $this->gameId, $this->layoutKey);
            $this->cache->save($guid, $layout->serializeToString(), 3600 * 24 * 30);
            $this->exists = true;
        } catch (\Exception $e) {
            //如果rcs返回的为不存在 这里直接单独处理
            $layout = new \Plu\Grpc\Services\RCS\LayoutDataResponse;
            if ($e->getCode() != self::ERR_LAYOUT_NOT_EXISTS) {
                $this->logger->error("get rcs error", [
                    'rcs.layoutId' => $this->layoutId,
                    'rcs.layoutKey'=> $this->layoutKey,
                    'code'         => $e->getCode(),
                    'msg'          => $e->getMessage(),
                    'file'         => $e->getFile(),
                    'line'         => $e->getLine(),
                    'trace'        => $e->getTraceAsString()
                ]);
                $layoutData = $this->cache->get($guid);
                $layout->mergeFromString($layoutData);
                $this->exists = true;
            } else {
                $this->exists = false;
            }
        }

        $this->layout = $layout;

        $items = [];
        $this->itemsByKey = [];
        foreach ($this->getStage() as $item) {
            $items[] = $item;
            $this->itemsByKey[$item['key']] = $item;
        }

        return $items;
    }

    public function getStageByKey($key) {
        if (is_null($this->itemsByKey)) {
            $this->getLayout();
        }

        return $this->itemsByKey[$key];
    }

    public function getStageListByKey() {
        if (is_null($this->itemsByKey)) {
            $this->getLayout();
        }

        return $this->itemsByKey;
    }


    public function getLastCursor() {
        return $this->lastCursor;
    }

    private function advert($resource){
        if($resource->getAdvert()){
            $advert['id']    = $resource->getAdvert()->getAdvertId();
            $advert['title'] = $resource->getAdvert()->getAdvertTitle();
            $advert['url']   = $resource->getAdvert()->getResourceUrl();

            return $advert;
        }

        return [];
    }


    private function game($resource){
        if($resource->getGame()){
            $game['id']   = $resource->getGame()->getGameId();
            $game['name'] = $resource->getGame()->getGameName();
            $info         = $this->gamesService->getGameInfoById($game['id']);
            $game['tag']  = $info['tag'];

            return $game;
        }

        return [];
    }


    private function match($resource){
        if($resource->getMatch()){
            $match['id'] = $resource->getMatch()->getMatchId();

            return $match;
        }

        return [];
    }


    private function location($resource){
        if($resource->getLocation()){
            $location['distance']   = $resource->getLocation()->getDistance();
            $location['latitude']   = $resource->getLocation()->getLatitude();
            $location['longtitude'] = $resource->getLocation()->getLongtitude();

            return $location;
        }

        return [];
    }


    private function userInfo($resource){
        if($resource->getUser()){
            $user['uid']    = $resource->getUser()->getUid();
            $user['name']   = $resource->getUser()->getName();
            $user['avatar'] = $resource->getUser()->getAvatar();

            return $user;
        }
        return [];
    }


    private function roomInfo($resource){
        if($resource->getRoom()){
            $room['broadcastBegin'] = $resource->getRoom()->getBroadcastBegin();
            $room['broadcastType']  = $resource->getRoom()->getBroadcastType();
            $room['fee']            = $resource->getRoom()->getFee();
            $room['lockable']       = $resource->getRoom()->getLockable();
            $room['liveSource']     = $resource->getRoom()->getLiveSource();
            $room['name']           = $resource->getRoom()->getName();
            $room['roomId']         = $resource->getRoom()->getRoomId();
            $room['domain']         = $resource->getRoom()->getDomain();
            $room['streamTypes']    = $resource->getRoom()->getStreamTypes();
            $room['tag']            = $resource->getRoom()->getTag();
            $room['title']          = $resource->getRoom()->getTitle();
            $room['preview']        = $resource->getRoom()->getPreview();
            $room['preview2']       = $resource->getRoom()->getPreview2();
            $room['views']          = $resource->getRoom()->getViews();
            $room['heatValue']      = $resource->getRoom()->getHeatValue();
            
            return $room;
        }

        return [];
    }


    public function formatChannel($data){
        $data = $this->format($data);

        $items = array();

        array_walk($data, function($room) use(&$items) {
            $items[] = array(
                "preview" => $room["preview"],
                "preview2" => $room['preview2'],
                "game" => array(array(
                    'id'   => $room['gameid'],
                    'name' => $room['gamename'],
                    'tag'  => $room['gametag']
                )),
                "channel" => array(
                    'id'                 => $room['id'],
                    'name'               => $room['name'],
                    'avatar'             => $room['avatar'],
                    'grade'              => $room['grade'],
                    'linkType'           => $room['linkType'],
                    'url'                => $room['url'],
                    'h5'                 => $room['h5'],
                    'status'             => $room['status'],
                    'broadcast_begin'    => $room['broadcast_begin'],
                    'broadcast_duration' => $room['broadcast_duration'],
                    'domain'             => $room['domain'],
                    'tag'                => $room['tag'],
                    'live_source'        => $room['live_source'],
                    'stream_types'       => $room['stream_types'],
                    'is_broadcast'       => $room['is_broadcast'],
                    'lockable'           => $room['lockable'],
                    'fee'                => $room['fee'],
                    'quality'            => $room['quality'],
                    'qualityRate'        => $room['qualityRate']
                ),
                "viewers"                =>  $room['views'],
                "heatValue"              => $room['heatValue'],
            );
        });

        return $items;
    }


    public function format($data){
        $items = array();

        $data = $this->getRoomInfoByRedis($data);

        array_walk($data, function($room) use(&$items) {
            $items[] = array(
                'id'      => (int)$room['room']['roomId'],
                'name'               => $room['room']['name'],
                'avatar'             => $room['user']['avatar'],
                'grade'              => (int)$room['room']['grade'],
                'linkType'           => (string)$room['linkType'],
                'url'                => $room['link'],
                'h5'                 => sprintf("http://m.longzhu.com/%s", $room['room']['domain']),
                'status'             => $room['room']['title'],
                'broadcast_begin'    => $room['room']['broadcastBegin'],
                'broadcast_duration' => (int)(time() - $room['room']['broadcastBegin']),
                'views'              => (int)$room['room']['views'],
                'domain'             => $room['room']['domain'],
                'tag'                => $room['room']['tag'],
                'live_source'        => (int)$room['room']['liveSource'],
                'stream_types'       => (int)$room['room']['streamTypes'],
                'is_broadcast'       => true,
                'lockable'           => (bool)$room['room']['lockable'],
                'fee'                => (int)$room['room']['fee'],
                'heatValue'          => (float)$room['room']['heatValue'],
                'gameid'             => (int)$room['game']['id'],
                'gametag'            => $room['game']['tag'],
                'gamename'           => $room['game']['name'],
                'preview'            => empty($room['cover']) ? $room['room']['preview']: $room['cover'],
                'preview2'           => $room['room']['preview2'],
                'quality'            => $room['room']['quality'],
                'qualityRate'        => $room['room']['qualityRate']
            );
        });

        return $items;
    }


    private function getRoomInfoByRedis($items){
        $roomIds = [];
        foreach ($items as $room) {
            $roomIds[] = $room['room']['roomId'];
        }

        $streamQuality = $this->roomRedis->getStreamQualityByRoomIds($roomIds);
        $grades = $this->roomRedis->getGrades($roomIds);

        $items = array_map(function($room) use ($streamQuality, $grades) {
            $roomId = $room['room']['roomId'];
            $room['room']['quality']     = $streamQuality[$roomId]['cornerName'];
            $room['room']['qualityRate'] = (int)$streamQuality[$roomId]['templateId'];
            $room['room']['grade']       = (int)$grades[$roomId];
            return $room;
        }, $items);

        return $items;
    }
}
